<?php

// +----------------------------------------------------------------------
// | 星数为来数字化开发引擎 [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2023~2024 http://xsframe.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 星数为来(杭州)科技有限公司
// +----------------------------------------------------------------------

namespace app\xs_ai\controller\api;

use xsframe\base\ApiBaseController;
use xsframe\exception\ApiException;
use xsframe\facade\service\OssServiceFacade;
use xsframe\util\FileUtil;
use xsframe\util\RandomUtil;

class Upload extends ApiBaseController
{
    /**
     * 上传文件
     * @return \think\response\Json
     * @throws ApiException
     */
    public function uploadFile(): \think\response\Json
    {
        $field = $this->params["file"] ?? ($this->params["filekey"] ?? 'file');
        $type = $this->params['type'] ?? '';

        if (!empty($this->params['type'])) {
            $type = explode("/", $this->params['type'])[0];
        }

        //接收文件
        if (empty($field) || empty($_FILES[$field]['name'])) {
            throw new ApiException('请选择要上传的文件');
        }

        //文件类型
        if (empty($type)) {
            throw new ApiException('文件类型不能为空');
        }

        $result = $this->doUpload($_FILES[$field], $type);
        return $this->success($result);
    }

    /**
     * 上传音频
     * @return \think\response\Json
     * @throws ApiException
     */
    public function uploadAudio(): \think\response\Json
    {
        $field = $this->params["file"] ?? ($this->params["filekey"] ?? '');

        //接收文件
        if (empty($field) || empty($_FILES[$field]['name'])) {
            throw new ApiException('请选择要上传的文件');
        }

        $result = $this->doUpload($_FILES[$field], 'audio');
        return $this->success($result);
    }

    /**
     * 上传base64文件
     * @return \think\response\Json|void
     * @throws ApiException
     */
    public function uploadBase64()
    {
        $base64_image_content = $this->params['base64'] ?? '';

        if (empty($base64_image_content)) {
            throw new ApiException('上传内容不能为空');
        }

        $result = $this->doUpload($base64_image_content, 'base64', '64');

        return $this->success($result);
    }

    /**
     * 上传图片
     * @throws ApiException
     */
    public function uploadImage(): \think\response\Json
    {
        $field = $this->params["file"] ?? ($this->params["filekey"] ?? 'file');

        if (empty($field) || empty($_FILES[$field]['name'])) {
            throw new ApiException("请选择要上传的图片");
        }

        $result = $this->doUpload($_FILES[$field]);

        return $this->success($result);
    }

    /**
     * 上传视频
     * @throws ApiException
     */
    public function uploadVideo(): \think\response\Json
    {
        $field = $this->params["file"] ?? ($this->params["filekey"] ?? 'file');

        //接收文件
        if (empty($field) || empty($_FILES[$field]['name'])) {
            throw new ApiException("请选择要上传的视频");
        }

        $result = $this->doUpload($_FILES[$field], 'video');

        return $this->success($result);
    }

    // 上传文件

    /**
     * type 0 图片 1音频 2视频 3base64
     * $folderKey 文件类型 比如说根据业务类型区分
     * @throws ApiException
     */
    private function doUpload($uploadFile, $uploadType = 'image', string $folderKey = ""): array
    {
        $rootPath = $this->iaRoot . "/public/attachment/";

        $path = $uploadType . "s" . "/" . $this->uniacid . "/" . $this->module . "/" . date('Y/m/');
        $path = str_replace("base64", "image", $path);

        if (!is_dir($rootPath . $path . $folderKey . "/")) {
            FileUtil::mkDirs($rootPath . $path . $folderKey . "/");
        }

        $filePath = "";
        switch ($uploadType) {
            case 'application':
            case 'image':
            case 'audio':
                $ext = $this->getFileExt($uploadFile, $uploadType);
                $fileName = $this->file_random_name($path, $ext, (empty($folderKey) ? "" : ($folderKey . "/")), 20);
                $filePath = $path . $fileName;
                @move_uploaded_file($uploadFile['tmp_name'], $rootPath . $filePath);
                break;
            case 'base64':
                if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $uploadFile, $result)) {
                    $ext = $result[2];
                    $harmType = ['asp', 'php', 'jsp', 'js', 'css', 'php3', 'php4', 'php5', 'ashx', 'aspx', 'exe', 'cgi'];
                    if (in_array(strtolower($ext), $harmType)) {
                        throw new ApiException("不允许上传此类文件1-{$ext}");
                    }
                    $allowExt = ['jpg', 'png'];
                    if (!in_array(strtolower($ext), $allowExt)) {
                        $ext = "png";
                    }

                    $fileName = $this->file_random_name($path, $ext, (empty($folderKey) ? "" : ($folderKey . "/")), 20);
                    $filePath = $path . $fileName;
                    @file_put_contents($rootPath . $filePath, base64_decode(str_replace($result[1], '', $uploadFile)));
                }
                break;
        }

        // 上传服务器 TODO 异步上传
        OssServiceFacade::uploadFile($filePath, $rootPath . $filePath);

        return [
            'url'      => tomedia(trim($filePath)),
            'filename' => $filePath,
        ];
    }

    /**
     * 获取文件后缀
     * @param $file
     * @return mixed|string
     * @throws
     */
    private function getFileExt($file, $type = 'image')
    {
        $harmType = ['asp', 'php', 'jsp', 'js', 'css', 'php3', 'php4', 'php5', 'ashx', 'aspx', 'exe', 'cgi'];
        if (empty($file)) {
            throw new ApiException('没有上传内容');
        }
        if (!in_array($type, ['image', 'thumb', 'voice', 'video', 'audio', 'file', 'application'])) {
            throw new ApiException('未知的上传类型');
        }

        $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if (empty($ext) && !empty($file['type'])) {
            $ext = strtolower(pathinfo($file['type'])['basename']);
        }

        $allowExt = [];
        $limit = 1024 * 20; // 20M
        switch ($type) {
            case 'thumb':
            case 'image':
                $allowExt = ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'ico', 'heic'];
                $limit = $limit * 1;
                break;
            case 'voice':
                break;
            case 'audio':
                $allowExt = ['mp3', 'wma', 'wav', 'amr'];
                $limit = $limit * 1;
                break;
            case 'file':
            case 'application':
                $allowExt = ['doc', 'docx', 'xls', 'xlsx', 'pdf', 'zip'];
                $limit = $limit * 1;
                break;
            case 'video':
                $allowExt = ['rm', 'rmvb', 'wmv', 'avi', 'mpg', 'mpeg', 'mp4'];
                $limit = $limit * 1;
                break;
        }

        if (!in_array(strtolower($ext), $allowExt) || in_array(strtolower($ext), $harmType)) {
            throw new ApiException("不允许上传此类文件");
        }

        if (!empty($limit) && $limit * 1024 < filesize($file['tmp_name'])) {
            throw new ApiException('上传的文件大小' . (round(filesize($file['tmp_name']) / 1024)) . "k超过限制，请上传小于 {$limit}k 的文件");
        }

        return $ext;
    }

    // 生成文件名称
    private function file_random_name($dir, $ext, $preFix = '', $length = 30): string
    {
        do {
            $filename = (empty($preFix) ? '' : $preFix . "_") . RandomUtil::random($length) . '.' . $ext;
        } while (file_exists($dir . $filename));
        return $filename;
    }
}